//go:build linux

package http_v3

import (
	"crypto/tls"
	go2_net "go2/net"
	"io"
	"net"
	"runtime"
	"syscall"
	"time"
)

type conn struct {
	fd          int
	update_time time.Time
	tlsConn     *tls.Conn
}

func NewConn(fd int, tlsConn *tls.Conn) *conn {
	return &conn{fd: fd, update_time: time.Now(), tlsConn: tlsConn}
}

// 优化：内联热路径函数
//go:inline
func (c *conn) Read(p []byte) (n int, e error) {
	c.update_time = time.Now()

	if c.tlsConn != nil {
		return c.tlsConn.Read(p)
	}

	// 优化：限制重试次数，避免无限循环
	const maxRetries = 3
	for retry := 0; retry < maxRetries; retry++ {
		n, e = syscall.Read(int(c.fd), p)
		if n > 0 {
			return
		}
		if e == syscall.EAGAIN {
			// 优化：短暂让出 CPU，避免忙等待
			runtime.Gosched()
			continue
		}
		return 0, io.EOF
	}
	// 超过重试次数，返回 EAGAIN 错误
	return 0, syscall.EAGAIN
}

// 优化：内联热路径函数
//go:inline
func (c *conn) Write(p []byte) (int, error) {
	if c.tlsConn != nil {
		return c.tlsConn.Write(p)
	}

	// 优化：批量写入，减少系统调用次数
	total := 0
	remaining := len(p)

	for remaining > 0 {
		n, err := syscall.Write(int(c.fd), p[total:])
		if err != nil {
			// 处理 EAGAIN/EWOULDBLOCK
			if err == syscall.EAGAIN || err == syscall.EWOULDBLOCK {
				runtime.Gosched()
				continue
			}
			return total, err
		}
		total += n
		remaining -= n
	}
	return total, nil
}

func (c *conn) Close() error {
	if c.tlsConn != nil {
		return c.tlsConn.Close()
	}
	return syscall.Close(int(c.fd))
}

// LocalAddr returns the local network address, if known.
func (c *conn) LocalAddr() net.Addr {
	if c.tlsConn != nil {
		return c.tlsConn.LocalAddr()
	}

	return nil
}

// RemoteAddr returns the remote network address, if known.
func (c *conn) RemoteAddr() net.Addr {
	if c.tlsConn != nil {
		return c.tlsConn.RemoteAddr()
	}

	return go2_net.GetAddr(c.fd)
}

// SetDeadline sets the read and write deadlines associated
// with the connection. It is equivalent to calling both
// SetReadDeadline and SetWriteDeadline.
//
// A deadline is an absolute time after which I/O operations
// fail instead of blocking. The deadline applies to all future
// and pending I/O, not just the immediately following call to
// Read or Write. After a deadline has been exceeded, the
// connection can be refreshed by setting a deadline in the future.
//
// If the deadline is exceeded a call to Read or Write or to other
// I/O methods will return an error that wraps os.ErrDeadlineExceeded.
// This can be tested using errors.Is(err, os.ErrDeadlineExceeded).
// The error's Timeout method will return true, but note that there
// are other possible errors for which the Timeout method will
// return true even if the deadline has not been exceeded.
//
// An idle timeout can be implemented by repeatedly extending
// the deadline after successful Read or Write calls.
//
// A zero value for t means I/O operations will not time out.
func (c *conn) SetDeadline(t time.Time) error {
	if c.tlsConn != nil {
		return c.tlsConn.SetDeadline(t)
	}
	return nil
}

// SetReadDeadline sets the deadline for future Read calls
// and any currently-blocked Read call.
// A zero value for t means Read will not time out.
func (c *conn) SetReadDeadline(t time.Time) error {
	if c.tlsConn != nil {
		return c.tlsConn.SetReadDeadline(t)
	}
	return nil
}

// SetWriteDeadline sets the deadline for future Write calls
// and any currently-blocked Write call.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
// A zero value for t means Write will not time out.
func (c *conn) SetWriteDeadline(t time.Time) error {
	if c.tlsConn != nil {
		return c.tlsConn.SetWriteDeadline(t)
	}
	return nil
}
